package utils

import (
	"errors"
	"log"
	"strconv"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

/**
 * 创建 grpc client connect
 *
 * @param string serviceName --------------------------------必传,要连接的服务名称
 * @param string tag ----------------------------------------非必传,要连接的服务标签【consul需要】
 * @return *grpc.ClientConn, error
 * @author huwl
 */
func NewGrpcClientConn(serviceName string, tag ...string) (*grpc.ClientConn, error) {
	// time.Sleep(time.Second * 10)

	// 获取服务地址
	target, err := GetServiceAddress(serviceName, tag...)
	if err != nil {
		return nil, err
	}

	log.Println("target =", target)
	// 创建JaegerTracer
	// jaegerTracer, closer, err := NewJaegerTracer(ServiceName, JaegerAddr)
	// if err != nil {
	// 	log.Fatalf("Failed to create JaegerTracer: %v", err)
	// }
	// defer closer.Close()
	// log.Println("jaegerTracer =", jaegerTracer)

	// 连接GRPC服务
	conn, err := grpc.Dial(
		target,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		// 加载jaegerTracer
		// grpc.WithUnaryInterceptor(grpc_opentracing.UnaryClientInterceptor(grpc_opentracing.WithTracer(jaegerTracer))),
	)

	// defer conn.Close()
	return conn, err
}

/**
 * 获取服务地址
 *
 * @param string serviceName --------------------------------必传,服务名称
 * @param string tag ----------------------------------------非必传,服务标签【consul需要】
 * @return string, error
 * @author huwl
 */
func GetServiceAddress(serviceName string, tag ...string) (target string, err error) {
	switch ServiceDiscovery {
	case "nacos":
		// 创建服务发现
		sr, err := NewNacosServiceDiscovery()
		if err != nil {
			return "", errors.New("Failed to create NacosServiceDiscovery: " + err.Error())
		}

		// 选择一个健康的实例
		modelInstance, err := sr.NacosSelectOneHealthyInstance(serviceName, "DEFAULT_GROUP", []string{"DEFAULT"})
		if err != nil {
			return "", errors.New("Failed to select one health instance: " + err.Error())
		}

		// 拼接target
		target = modelInstance.Ip + ":" + strconv.FormatUint(modelInstance.Port, 10)

	case "consul":
		// 读取consul配置文件
		consulConf, err := GetConfig("consul", "yml")
		if err != nil {
			return "", errors.New("Failed to read consul config: " + err.Error())
		}

		// 创建服务发现
		sd, err := NewConsulServiceDiscovery(
			consulConf.GetString(UserSrvEnv+".addrs"),
			consulConf.GetString(UserSrvEnv+".secret_id"),
		)
		if err != nil {
			return "", errors.New("Failed to create ConsulServiceDiscovery: " + err.Error())
		}

		// 选择一个健康的服务
		healthyService, err := sd.SelectOneHealthyService(serviceName, tag[0])
		if err != nil {
			return "", errors.New("Failed to select OneHealthyService: " + err.Error())
		}

		// 拼接target
		target = healthyService.Address + ":" + strconv.Itoa(healthyService.Port)

	case "etcd":
		// 读取 etcd 配置信息
		etcdConfig, err := GetConfig("etcd", "yml")
		if err != nil {
			return "", errors.New("Failed to read etcd config: " + err.Error())
		}

		// 创建服务发现
		watchedKey := etcdConfig.GetString(UserSrvEnv+".service_prefix") + "/" + serviceName
		sd, err := NewEtcdServiceDiscovery(
			etcdConfig.GetStringSlice(UserSrvEnv+".addrs"),
			etcdConfig.GetString(UserSrvEnv+".username"),
			etcdConfig.GetString(UserSrvEnv+".password"),
			watchedKey,
		)
		if err != nil {
			return "", errors.New("Failed to create ServiceDiscovery: " + err.Error())
		}

		// 发现服务
		err = sd.DiscoverServices()
		if err != nil {
			return "", errors.New("Failed to DiscoverServices: " + err.Error())
		}

		// 监控服务
		go func() {
			err := sd.WatchServices()
			if err != nil {
				log.Fatalf("Failed to watch services: %v", err)
			}
		}()

		// 获取服务地址
		for _, service := range sd.services {
			target = service.Address
		}
	}

	return
}
